home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gsciemap.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  16.5 KB  |  498 lines

  1. /* Copyright (C) 1992, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gsciemap.c,v 1.3.2.1 2000/10/26 13:06:34 igorm Exp $ */
  20. /* CIE color rendering */
  21. #include "math_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gxcspace.h"        /* for gxcie.c */
  25. #include "gxarith.h"
  26. #include "gxcie.h"
  27. #include "gxdevice.h"        /* for gxcmap.h */
  28. #include "gxcmap.h"
  29. #include "gxistate.h"
  30.  
  31. /* Compute a cache index as (vin - base) * factor. */
  32. /* vin, base, factor, and the result are cie_cached_values. */
  33. /* We know that the result doesn't exceed (gx_cie_cache_size - 1) << fbits. */
  34. #define LOOKUP_INDEX(vin, pcache, fbits)\
  35.   ((vin) <= (pcache)->vecs.params.base ? 0 :\
  36.    (vin) >= (pcache)->vecs.params.limit ? (gx_cie_cache_size - 1) << (fbits) :\
  37.    cie_cached_product2int( ((vin) - (pcache)->vecs.params.base),\
  38.                (pcache)->vecs.params.factor, fbits ))
  39. #define LOOKUP_VALUE(vin, pcache)\
  40.   ((pcache)->vecs.values[LOOKUP_INDEX(vin, pcache, 0)])
  41.  
  42. /*
  43.  * Test whether a CIE rendering has been defined; ensure that the joint
  44.  * caches are loaded.  Note that the procedure may return if no rendering
  45.  * has been defined, and returns if an error occurs.
  46.  */
  47. #define CIE_CHECK_RENDERING(pcs, pconc, pis, do_exit)\
  48.   BEGIN\
  49.     if (pis->cie_render == 0) {\
  50.     /* No rendering has been defined yet: return black. */\
  51.     pconc[0] = pconc[1] = pconc[2] = frac_0;\
  52.     do_exit;\
  53.     }\
  54.     if (pis->cie_joint_caches->status != CIE_JC_STATUS_COMPLETED) {\
  55.     int code = gs_cie_jc_complete(pis, pcs);\
  56. \
  57.     if (code < 0)\
  58.         return code;\
  59.     }\
  60.   END
  61.  
  62. /* Forward references */
  63. private int cie_remap_finish(P4(cie_cached_vector3,
  64.                 frac *, const gs_imager_state *,
  65.                 const gs_color_space *));
  66. private void cie_lookup_mult3(P2(cie_cached_vector3 *,
  67.                  const gx_cie_vector_cache *));
  68.  
  69. #ifdef DEBUG
  70. private void
  71. cie_lookup_map3(cie_cached_vector3 * pvec,
  72.         const gx_cie_vector_cache * pc /*[3] */ , const char *cname)
  73. {
  74.     if_debug5('c', "[c]lookup %s 0x%lx [%g %g %g]\n",
  75.           (const char *)cname, (ulong) pc,
  76.           cie_cached2float(pvec->u), cie_cached2float(pvec->v),
  77.           cie_cached2float(pvec->w));
  78.     cie_lookup_mult3(pvec, pc);
  79.     if_debug3('c', "        =[%g %g %g]\n",
  80.           cie_cached2float(pvec->u), cie_cached2float(pvec->v),
  81.           cie_cached2float(pvec->w));
  82. }
  83. #else
  84. #  define cie_lookup_map3(pvec, pc, cname) cie_lookup_mult3(pvec, pc)
  85. #endif
  86.  
  87. /* Render a CIEBasedDEFG color. */
  88. int
  89. gx_concretize_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs,
  90.               frac * pconc, const gs_imager_state * pis)
  91. {
  92.     const gs_cie_defg *pcie = pcs->params.defg;
  93.     int i;
  94.     fixed hijk[4];
  95.     frac abc[3];
  96.     cie_cached_vector3 vec3;
  97.  
  98.     if_debug4('c', "[c]concretize DEFG [%g %g %g %g]\n",
  99.           pc->paint.values[0], pc->paint.values[1],
  100.           pc->paint.values[2], pc->paint.values[3]);
  101.     CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
  102.  
  103.     /*
  104.      * Apply DecodeDEFG, including restriction to RangeHIJK and scaling to
  105.      * the Table dimensions.
  106.      */
  107.     for (i = 0; i < 4; ++i) {
  108.     int tdim = pcie->Table.dims[i] - 1;
  109.     double factor = pcie->caches_defg.DecodeDEFG[i].floats.params.factor;
  110.     double v0 = pc->paint.values[i];
  111.     const gs_range *const rangeDEFG = &pcie->RangeDEFG.ranges[i];
  112.     double value =
  113.         (v0 < rangeDEFG->rmin ? 0.0 :
  114.          v0 > rangeDEFG->rmax ? factor :
  115.          (v0 - rangeDEFG->rmin) * factor /
  116.            (rangeDEFG->rmax - rangeDEFG->rmin));
  117.     int vi = (int)value;
  118.     double vf = value - vi;
  119.     double v = pcie->caches_defg.DecodeDEFG[i].floats.values[vi];
  120.  
  121.     if (vf != 0 && vi < factor)
  122.         v += vf *
  123.         (pcie->caches_defg.DecodeDEFG[i].floats.values[vi + 1] - v);
  124.     v = (v < 0 ? 0 : v > tdim ? tdim : v);
  125.     hijk[i] = float2fixed(v);
  126.     }
  127.     /* Apply Table. */
  128.     gx_color_interpolate_linear(hijk, &pcie->Table, abc);
  129.     vec3.u = float2cie_cached(frac2float(abc[0]));
  130.     vec3.v = float2cie_cached(frac2float(abc[1]));
  131.     vec3.w = float2cie_cached(frac2float(abc[2]));
  132.     /* Apply DecodeABC and MatrixABC. */
  133.     if (!pis->cie_joint_caches->skipDecodeABC)
  134.     cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC[0],
  135.             "Decode/MatrixABC");
  136.     cie_remap_finish(vec3, pconc, pis, pcs);
  137.     return 0;
  138. }
  139.  
  140. /* Render a CIEBasedDEF color. */
  141. int
  142. gx_concretize_CIEDEF(const gs_client_color * pc, const gs_color_space * pcs,
  143.              frac * pconc, const gs_imager_state * pis)
  144. {
  145.     const gs_cie_def *pcie = pcs->params.def;
  146.     int i;
  147.     fixed hij[3];
  148.     frac abc[3];
  149.     cie_cached_vector3 vec3;
  150.  
  151.     if_debug3('c', "[c]concretize DEF [%g %g %g]\n",
  152.           pc->paint.values[0], pc->paint.values[1],
  153.           pc->paint.values[2]);
  154.     CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
  155.  
  156.     /*
  157.      * Apply DecodeDEF, including restriction to RangeHIJ and scaling to
  158.      * the Table dimensions.
  159.      */
  160.     for (i = 0; i < 3; ++i) {
  161.     int tdim = pcie->Table.dims[i] - 1;
  162.     double factor = pcie->caches_def.DecodeDEF[i].floats.params.factor;
  163.     double v0 = pc->paint.values[i];
  164.     const gs_range *const rangeDEF = &pcie->RangeDEF.ranges[i];
  165.     double value =
  166.         (v0 < rangeDEF->rmin ? 0.0 :
  167.          v0 > rangeDEF->rmax ? factor :
  168.          (v0 - rangeDEF->rmin) * factor /
  169.            (rangeDEF->rmax - rangeDEF->rmin));
  170.     int vi = (int)value;
  171.     double vf = value - vi;
  172.     double v = pcie->caches_def.DecodeDEF[i].floats.values[vi];
  173.  
  174.     if (vf != 0 && vi < factor)
  175.         v += vf *
  176.         (pcie->caches_def.DecodeDEF[i].floats.values[vi + 1] - v);
  177.     v = (v < 0 ? 0 : v > tdim ? tdim : v);
  178.     hij[i] = float2fixed(v);
  179.     }
  180.     /* Apply Table. */
  181.     gx_color_interpolate_linear(hij, &pcie->Table, abc);
  182.     vec3.u = float2cie_cached(frac2float(abc[0]));
  183.     vec3.v = float2cie_cached(frac2float(abc[1]));
  184.     vec3.w = float2cie_cached(frac2float(abc[2]));
  185.     /* Apply DecodeABC and MatrixABC. */
  186.     if (!pis->cie_joint_caches->skipDecodeABC)
  187.     cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC[0],
  188.             "Decode/MatrixABC");
  189.     cie_remap_finish(vec3, pconc, pis, pcs);
  190.     return 0;
  191. }
  192.  
  193. /* Render a CIEBasedABC color. */
  194. /* We provide both remap and concretize, but only the former */
  195. /* needs to be efficient. */
  196. int
  197. gx_remap_CIEABC(const gs_client_color * pc, const gs_color_space * pcs,
  198.     gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
  199.         gs_color_select_t select)
  200. {
  201.     frac conc[4];
  202.     cie_cached_vector3 vec3;
  203.  
  204.     if_debug3('c', "[c]remap CIEABC [%g %g %g]\n",
  205.           pc->paint.values[0], pc->paint.values[1],
  206.           pc->paint.values[2]);
  207.     CIE_CHECK_RENDERING(pcs, conc, pis, goto map3);
  208.     vec3.u = float2cie_cached(pc->paint.values[0]);
  209.     vec3.v = float2cie_cached(pc->paint.values[1]);
  210.     vec3.w = float2cie_cached(pc->paint.values[2]);
  211.  
  212.     /* Apply DecodeABC and MatrixABC. */
  213.     if (!pis->cie_joint_caches->skipDecodeABC) {
  214.     const gs_cie_abc *pcie = pcs->params.abc;
  215.  
  216.     cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC[0],
  217.             "Decode/MatrixABC");
  218.     }
  219.     switch (cie_remap_finish(vec3 /* LMN */, conc, pis, pcs)) {
  220.     case 4:
  221.         if_debug4('c', "[c]=CMYK [%g %g %g %g]\n",
  222.               frac2float(conc[0]), frac2float(conc[1]),
  223.               frac2float(conc[2]), frac2float(conc[3]));
  224.         gx_remap_concrete_cmyk(conc[0], conc[1], conc[2], conc[3],
  225.                    pdc, pis, dev, select);
  226.         return 0;
  227.     default:    /* Can't happen. */
  228.         return_error(gs_error_unknownerror);
  229.     case 3:
  230.         ;
  231.     }
  232. map3:
  233.     if_debug3('c', "[c]=RGB [%g %g %g]\n",
  234.           frac2float(conc[0]), frac2float(conc[1]),
  235.           frac2float(conc[2]));
  236.     gx_remap_concrete_rgb(conc[0], conc[1], conc[2], pdc, pis,
  237.               dev, select);
  238.     return 0;
  239. }
  240. int
  241. gx_concretize_CIEABC(const gs_client_color * pc, const gs_color_space * pcs,
  242.              frac * pconc, const gs_imager_state * pis)
  243. {
  244.     const gs_cie_abc *pcie = pcs->params.abc;
  245.     cie_cached_vector3 vec3;
  246.  
  247.     if_debug3('c', "[c]concretize CIEABC [%g %g %g]\n",
  248.           pc->paint.values[0], pc->paint.values[1],
  249.           pc->paint.values[2]);
  250.     CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
  251.  
  252.     vec3.u = float2cie_cached(pc->paint.values[0]);
  253.     vec3.v = float2cie_cached(pc->paint.values[1]);
  254.     vec3.w = float2cie_cached(pc->paint.values[2]);
  255.     if (!pis->cie_joint_caches->skipDecodeABC)
  256.     cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC[0],
  257.             "Decode/MatrixABC");
  258.     cie_remap_finish(vec3, pconc, pis, pcs);
  259.     return 0;
  260. }
  261.  
  262. /* Render a CIEBasedA color. */
  263. int
  264. gx_concretize_CIEA(const gs_client_color * pc, const gs_color_space * pcs,
  265.            frac * pconc, const gs_imager_state * pis)
  266. {
  267.     const gs_cie_a *pcie = pcs->params.a;
  268.     cie_cached_value a = float2cie_cached(pc->paint.values[0]);
  269.     cie_cached_vector3 vlmn;
  270.  
  271.     if_debug1('c', "[c]concretize CIEA %g\n", pc->paint.values[0]);
  272.     CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
  273.  
  274.     /* Apply DecodeA and MatrixA. */
  275.     if (!pis->cie_joint_caches->skipDecodeABC)
  276.     vlmn = LOOKUP_VALUE(a, &pcie->caches.DecodeA);
  277.     else
  278.     vlmn.u = vlmn.v = vlmn.w = a;
  279.     cie_remap_finish(vlmn, pconc, pis, pcs);
  280.     return 0;
  281. }
  282.  
  283. /* Common rendering code. */
  284. /* Return 3 if RGB, 4 if CMYK. */
  285. private int
  286. cie_remap_finish(cie_cached_vector3 vec3, frac * pconc,
  287.          const gs_imager_state * pis, const gs_color_space *pcs)
  288. {
  289.     const gs_cie_render *pcrd = pis->cie_render;
  290.     const gx_cie_joint_caches *pjc = pis->cie_joint_caches;
  291.     const gs_const_string *table = pcrd->RenderTable.lookup.table;
  292.     int tabc[3];        /* indices for final EncodeABC lookup */
  293.  
  294.     /* Apply DecodeLMN, MatrixLMN(decode), and MatrixPQR. */
  295.     if (!pjc->skipDecodeLMN)
  296.     cie_lookup_map3(&vec3 /* LMN => PQR */, &pjc->DecodeLMN[0],
  297.             "Decode/MatrixLMN+MatrixPQR");
  298.  
  299.     /* Apply TransformPQR, MatrixPQR', and MatrixLMN(encode). */
  300.     if (!pjc->skipPQR)
  301.     cie_lookup_map3(&vec3 /* PQR => LMN */, &pjc->TransformPQR[0],
  302.             "Transform/Matrix'PQR+MatrixLMN");
  303.  
  304.     /* Apply EncodeLMN and MatrixABC(encode). */
  305.     if (!pjc->skipEncodeLMN)
  306.     cie_lookup_map3(&vec3 /* LMN => ABC */, &pcrd->caches.EncodeLMN[0],
  307.             "EncodeLMN+MatrixABC");
  308.  
  309.     /* MatrixABCEncode includes the scaling of the EncodeABC */
  310.     /* cache index. */
  311. #define SET_TABC(i, t)\
  312.   BEGIN\
  313.     tabc[i] = cie_cached2int(vec3 /*ABC*/.t - pcrd->EncodeABC_base[i],\
  314.                  _cie_interpolate_bits);\
  315.     if ((uint)tabc[i] > (gx_cie_cache_size - 1) << _cie_interpolate_bits)\
  316.     tabc[i] = (tabc[i] < 0 ? 0 :\
  317.            (gx_cie_cache_size - 1) << _cie_interpolate_bits);\
  318.   END
  319.     SET_TABC(0, u);
  320.     SET_TABC(1, v);
  321.     SET_TABC(2, w);
  322. #undef SET_TABC
  323.     if (table == 0) {
  324.     /*
  325.      * No further transformation.
  326.      * The final mapping step includes both restriction to
  327.      * the range [0..1] and conversion to fracs.
  328.      */
  329. #define EABC(i)\
  330.   cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.fracs.values, tabc[i])
  331.     pconc[0] = EABC(0);
  332.     pconc[1] = EABC(1);
  333.     pconc[2] = EABC(2);
  334. #undef EABC
  335.     return 3;
  336.     } else {
  337.     /*
  338.      * Use the RenderTable.
  339.      */
  340.     int m = pcrd->RenderTable.lookup.m;
  341.  
  342. #define RT_LOOKUP(j, i) pcrd->caches.RenderTableT[j].fracs.values[i]
  343. #ifdef CIE_RENDER_TABLE_INTERPOLATE
  344.  
  345.     /*
  346.      * The final mapping step includes restriction to the
  347.      * ranges [0..dims[c]] as ints with interpolation bits.
  348.      */
  349.     fixed rfix[3];
  350.  
  351. #define EABC(i)\
  352.   cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.ints.values, tabc[i])
  353. #define FABC(i)\
  354.   (EABC(i) << (_fixed_shift - _cie_interpolate_bits))
  355.     rfix[0] = FABC(0);
  356.     rfix[1] = FABC(1);
  357.     rfix[2] = FABC(2);
  358. #undef FABC
  359. #undef EABC
  360.     if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%g,%g,%g\n",
  361.           cie_cached2float(vec3.u), cie_cached2float(vec3.v),
  362.           cie_cached2float(vec3.w), fixed2float(rfix[0]),
  363.           fixed2float(rfix[1]), fixed2float(rfix[2]));
  364.     gx_color_interpolate_linear(rfix, &pcrd->RenderTable.lookup,
  365.                     pconc);
  366.     if_debug3('c', "[c]  interpolated => %g,%g,%g\n",
  367.           frac2float(pconc[0]), frac2float(pconc[1]),
  368.           frac2float(pconc[2]));
  369.     if (!pcrd->caches.RenderTableT_is_identity) {
  370.         /* Map the interpolated values. */
  371. #define frac2cache_index(v) frac2bits(v, gx_cie_log2_cache_size)
  372.         pconc[0] = RT_LOOKUP(0, frac2cache_index(pconc[0]));
  373.         pconc[1] = RT_LOOKUP(1, frac2cache_index(pconc[1]));
  374.         pconc[2] = RT_LOOKUP(2, frac2cache_index(pconc[2]));
  375.         if (m > 3)
  376.         pconc[3] = RT_LOOKUP(3, frac2cache_index(pconc[3]));
  377. #undef frac2cache_index
  378.     }
  379.  
  380. #else /* !CIE_RENDER_TABLE_INTERPOLATE */
  381.  
  382.     /*
  383.      * The final mapping step includes restriction to the ranges
  384.      * [0..dims[c]], plus scaling of the indices in the strings.
  385.      */
  386. #define RI(i)\
  387.   pcrd->caches.EncodeABC[i].ints.values[tabc[i] >> _cie_interpolate_bits]
  388.     int ia = RI(0);
  389.     int ib = RI(1);        /* pre-multiplied by m * NC */
  390.     int ic = RI(2);        /* pre-multiplied by m */
  391.     const byte *prtc = table[ia].data + ib + ic;
  392.  
  393.     /* (*pcrd->RenderTable.T)(prtc, m, pcrd, pconc); */
  394.  
  395.     if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%d,%d,%d\n",
  396.           cie_cached2float(vec3.u), cie_cached2float(vec3.v),
  397.           cie_cached2float(vec3.w), ia, ib, ic);
  398.     if (pcrd->caches.RenderTableT_is_identity) {
  399.         pconc[0] = byte2frac(prtc[0]);
  400.         pconc[1] = byte2frac(prtc[1]);
  401.         pconc[2] = byte2frac(prtc[2]);
  402.         if (m > 3)
  403.         pconc[3] = byte2frac(prtc[3]);
  404.     } else {
  405. #if gx_cie_log2_cache_size == 8
  406. #  define byte2cache_index(b) (b)
  407. #else
  408. # if gx_cie_log2_cache_size > 8
  409. #  define byte2cache_index(b)\
  410.     ( ((b) << (gx_cie_log2_cache_size - 8)) +\
  411.       ((b) >> (16 - gx_cie_log2_cache_size)) )
  412. # else                /* < 8 */
  413. #  define byte2cache_index(b) ((b) >> (8 - gx_cie_log2_cache_size))
  414. # endif
  415. #endif
  416.         pconc[0] = RT_LOOKUP(0, byte2cache_index(prtc[0]));
  417.         pconc[1] = RT_LOOKUP(1, byte2cache_index(prtc[1]));
  418.         pconc[2] = RT_LOOKUP(2, byte2cache_index(prtc[2]));
  419.         if (m > 3)
  420.         pconc[3] = RT_LOOKUP(3, byte2cache_index(prtc[3]));
  421. #undef byte2cache_index
  422.     }
  423.  
  424. #endif /* !CIE_RENDER_TABLE_INTERPOLATE */
  425. #undef RI
  426. #undef RT_LOOKUP
  427.     return m;
  428.     }
  429. }
  430.  
  431. /* Look up 3 values in a cache, with cached post-multiplication. */
  432. private void
  433. cie_lookup_mult3(cie_cached_vector3 * pvec,
  434.          const gx_cie_vector_cache * pc /*[3] */ )
  435. {
  436. /****** Interpolating at intermediate stages doesn't seem to ******/
  437. /****** make things better, and slows things down, so....    ******/
  438. #ifdef CIE_INTERPOLATE_INTERMEDIATE
  439.     /* Interpolate between adjacent cache entries. */
  440.     /* This is expensive! */
  441. #ifdef CIE_CACHE_USE_FIXED
  442. #  define lookup_interpolate_between(v0, v1, i, ftemp)\
  443.      cie_interpolate_between(v0, v1, i)
  444. #else
  445.     float ftu, ftv, ftw;
  446.  
  447. #  define lookup_interpolate_between(v0, v1, i, ftemp)\
  448.      ((v0) + ((v1) - (v0)) *\
  449.       ((ftemp = float_rshift(i, _cie_interpolate_bits)), ftemp - (int)ftemp))
  450. #endif
  451.  
  452.     cie_cached_value iu =
  453.      LOOKUP_INDEX(pvec->u, pc, _cie_interpolate_bits);
  454.     const cie_cached_vector3 *pu =
  455.     &pc[0].vecs.values[(int)cie_cached_rshift(iu,
  456.                           _cie_interpolate_bits)];
  457.     const cie_cached_vector3 *pu1 =
  458.     (iu >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ?
  459.      pu : pu + 1);
  460.  
  461.     cie_cached_value iv =
  462.     LOOKUP_INDEX(pvec->v, pc + 1, _cie_interpolate_bits);
  463.     const cie_cached_vector3 *pv =
  464.     &pc[1].vecs.values[(int)cie_cached_rshift(iv,
  465.                           _cie_interpolate_bits)];
  466.     const cie_cached_vector3 *pv1 =
  467.     (iv >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ?
  468.      pv : pv + 1);
  469.  
  470.     cie_cached_value iw =
  471.     LOOKUP_INDEX(pvec->w, pc + 2, _cie_interpolate_bits);
  472.     const cie_cached_vector3 *pw =
  473.     &pc[2].vecs.values[(int)cie_cached_rshift(iw,
  474.                           _cie_interpolate_bits)];
  475.     const cie_cached_vector3 *pw1 =
  476.     (iw >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ?
  477.      pw : pw + 1);
  478.  
  479.     pvec->u = lookup_interpolate_between(pu->u, pu1->u, iu, ftu) +
  480.     lookup_interpolate_between(pv->u, pv1->u, iv, ftv) +
  481.     lookup_interpolate_between(pw->u, pw1->u, iw, ftw);
  482.     pvec->v = lookup_interpolate_between(pu->v, pu1->v, iu, ftu) +
  483.     lookup_interpolate_between(pv->v, pv1->v, iv, ftv) +
  484.     lookup_interpolate_between(pw->v, pw1->v, iw, ftw);
  485.     pvec->w = lookup_interpolate_between(pu->w, pu1->w, iu, ftu) +
  486.     lookup_interpolate_between(pv->w, pv1->w, iv, ftv) +
  487.     lookup_interpolate_between(pw->w, pw1->w, iw, ftw);
  488. #else
  489.     const cie_cached_vector3 *pu = &LOOKUP_VALUE(pvec->u, pc);
  490.     const cie_cached_vector3 *pv = &LOOKUP_VALUE(pvec->v, pc + 1);
  491.     const cie_cached_vector3 *pw = &LOOKUP_VALUE(pvec->w, pc + 2);
  492.  
  493.     pvec->u = pu->u + pv->u + pw->u;
  494.     pvec->v = pu->v + pv->v + pw->v;
  495.     pvec->w = pu->w + pv->w + pw->w;
  496. #endif
  497. }
  498.